package com.gitee.apanlh.util.net.http;

import com.gitee.apanlh.exp.HttpConnectionException;
import com.gitee.apanlh.exp.HttpException;
import com.gitee.apanlh.util.io.IOUtils;
import com.gitee.apanlh.util.net.http.handler.HttpInterceptor;
import com.gitee.apanlh.util.net.http.handler.HttpInterceptorContext;
import com.gitee.apanlh.util.net.http.io.HttpResponseInputStream;
import com.gitee.apanlh.util.net.http.log.HttpLog;
import com.gitee.apanlh.util.reflection.ClassTypeUtils;
import com.gitee.apanlh.web.http.HttpMethod;

/**	
 * 	HTTP执行器
 * 	<br>如果需要实现一些请求前或请求后的操作可添加{@link HttpInterceptor}类
 * 	
 * 	@author Pan
 */
public class HttpExecutor {
	
	/** HTTP客户端 */
	private HttpClient httpClient;
	/** HTTP请求对象 */
	private HttpRequest httpRequest;
	/** HTTP请求状态 */
	private HttpStatus httpStatus;
	/** HTTP日志 */
	private HttpLog httpLog;
	/** HTTP拦截器上下文 */
	private HttpInterceptorContext httpInterceptorContext;
	/** HTTP响应输入流 */
    private HttpResponseInputStream httpResponseInputStream;
    
	/**
	 * 	默认构造函数
	 * 	
	 * 	@author Pan
	 */
	@SuppressWarnings("unused")
	private HttpExecutor() {
		//	不允许外部实例
		super();
	}
	
	/**	
	 * 	构造-加载HTTPRequest
	 * 	<br>如果日志开启则创建HTTP日志
	 * 	<br>默认初始化HTTPClient首次URL值(不会创建连接)
	 * 	
	 * 	@author Pan
	 * 	@param 	httpRequest					HTTP请求对象
	 * 	@param 	httpInterceptorContext		拦截器上下文
	 */
	HttpExecutor(HttpRequest httpRequest, HttpInterceptorContext httpInterceptorContext) {
		this.httpRequest = httpRequest;
		this.httpLog = HttpLog.create(httpRequest);
		this.httpInterceptorContext = httpInterceptorContext;
		this.httpClient = HttpClient.create(httpRequest.getUrl());
	}
	
	/**	
	 * 	执行-发送HTTP请求
	 * 	<br>不存在配置时根据请求类型来启动默认配置
	 * 	<br>出现异常将关闭客户端
	 * 	
	 * 	@author Pan
	 * 	@return	HttpResponse
	 */
	public HttpResponse execute() {
		httpInterceptorContext.getRequestPreInterceptorChain().proceed(httpRequest, httpClient);
		httpInterceptorContext.getRequestInterceptorChain().proceed(httpRequest, httpClient);
		try {
			send();
			HttpResponse httpResponse = new HttpResponse(httpRequest, httpStatus, httpClient, httpResponseInputStream, httpLog);
			return httpInterceptorContext.getResponseInterceptorChain().proceed(httpResponse);
		} catch (Exception e) {
			IOUtils.close(httpClient, httpResponseInputStream);
			throw new HttpConnectionException(e.getMessage(), e);
		}
	}
	
	/**
	 * 	写入请求
	 * 	<br>并不意味着数据已经被发送
	 * 	<br>写入过程如果出现异常，则会自动关闭流
	 * 	
	 * 	@author Pan
	 */
	private void write() throws HttpException {
		HttpMethod method = httpRequest.getMethod();
		HttpBody body = httpRequest.getBody();
		HttpConfig config = httpRequest.getConfig();
		
		httpLog.writeRequest();
		
		//	如果消息为空则不写入
		if (HttpMethod.GET.equals(method)
				|| body == null 
				|| body.hasRest()
				|| body.hasQueryParams()
				|| body.getRequestBody() == null) {
			return ;
		}
		
		Object data = body.getRequestBody();
		
		if (ClassTypeUtils.isString(data)) {
			IOUtils.write((String) data, httpClient.getOutputStream(), config.getCharset());
			return ;
		}
		IOUtils.write((byte[]) data, httpClient.getOutputStream());
	}
	
	/**	
     * 	发送请求，读取服务器的响应内容
     * 	
     * 	@author Pan
	 * 	@throws HttpException	出现异常则抛出
     */
    private void send() throws HttpException {
    	write();
    	
    	this.httpStatus = HttpStatus.create(httpClient);
    	this.httpLog.setHttpStatus(this.httpStatus);
    	this.httpResponseInputStream = httpClient.getInputStream(httpStatus);
    }
    
	/**	
	 * 	获取请求日志
	 * 	
	 * 	@author Pan
	 * 	@return	HttpLog
	 */
	public HttpLog getHttpLog() {
		return httpLog;
	}

	/**	
	 * 	构建-HTTP执行器
	 * 	
	 * 	@author Pan
	 * 	@param 	httpRequest					HTTP请求对象
	 * 	@param 	httpInterceptorContext		拦截器上下文
	 * 	@return	HttpExecutor
	 */
	public static HttpExecutor create(HttpRequest httpRequest, HttpInterceptorContext httpInterceptorContext) {
		return new HttpExecutor(httpRequest, httpInterceptorContext);
	}
}
